package net.j4love.mybatis.kit.plugin;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class XMLEnvConfiguration {

    private static final Map<String , Configuration> ENV_CONFIGS = new ConcurrentHashMap<>(4);
    private String defaultEnvId;
    private Configuration masterConfiguration;
    private Integer slaveEnvSize;
    private static volatile XMLEnvConfiguration xmlEnvConfiguration;

    private XMLEnvConfiguration(String resource) throws IOException {
        InputStream inputStream = Resources.getResourceAsStream(resource);
        byte[] bytes = IOUtils.toByteArray(inputStream);
        XPathParser xPathParser = new XPathParser(new ByteArrayInputStream(bytes), true, null, new XMLMapperEntityResolver());
        XNode rootNode = xPathParser.evalNode("/configuration");
        XNode environmentsNode = rootNode.evalNode("environments");
        this.defaultEnvId = environmentsNode.getStringAttribute("default");
        for (XNode child : environmentsNode.getChildren()) {
            String envId = child.getStringAttribute("id");
            XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(new ByteArrayInputStream(bytes), envId, null);
            Configuration configuration = xmlConfigBuilder.parse();
            ENV_CONFIGS.put(envId , configuration);
            if (StringUtils.equals(envId , this.defaultEnvId)) {
                this.masterConfiguration = configuration;
            }
        }
        this.slaveEnvSize = ENV_CONFIGS.size() - 1;
    }

    public List<Configuration> getSlaveConfigurations() {
        Collection<Configuration> configurations = ENV_CONFIGS.values();
        configurations.remove(ENV_CONFIGS.get(this.defaultEnvId));
        return new ArrayList<>(configurations);
    }

    public Configuration getMasterConfiguration() {
        return masterConfiguration;
    }

    public String getDefaultEnvId() {
        return defaultEnvId;
    }

    public Integer getSlaveEnvSize() {
        return slaveEnvSize;
    }

    public static XMLEnvConfiguration getXmlEnvConfigParser(String resource) throws IOException {
        if (xmlEnvConfiguration == null) {
           synchronized (XMLEnvConfiguration.class) {
                if (xmlEnvConfiguration == null) {
                    xmlEnvConfiguration = new XMLEnvConfiguration(resource);
                }
            }
        }
        return xmlEnvConfiguration;
    }

}
